package com.cats.bi.aggservice.impl;

import com.cats.bi.aggservice.DataSourceAggService;
import com.cats.bi.aggservice.FilterAggService;
import com.cats.bi.aggservice.ViewAggService;
import com.cats.bi.chartservice.ChartDataService;
import com.cats.bi.enums.ActionTypeEnum;
import com.cats.bi.enums.FilterEnum;
import com.cats.bi.enums.OperatorEnum;
import com.cats.bi.enums.RelationEnum;
import com.cats.bi.exception.GetException;
import com.cats.bi.exception.SaveException;
import com.cats.bi.pojo.dto.*;
import com.cats.bi.pojo.model.*;
import com.cats.bi.service.*;
import com.cats.bi.sqltool.basic.Select;
import com.cats.echarts.utils.GsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author duxiaobo
 * @date 2021/8/102:59 下午
 */
@Service
@Slf4j
public class ViewAggServiceImpl implements ViewAggService {

    @Autowired
    private ViewService viewService;
    @Autowired
    private DimensionService dimensionService;
    @Autowired
    private MeasureService measureService;
    @Autowired
    private DataSourceAggService dataSourceAggService;
    @Autowired
    private SqlAssemblyService sqlAssemblyService;
    @Autowired
    private FilterAggService filterAggService;
    @Autowired
    private ActionService actionService;
    @Autowired
    private FilterComponentService filterComponentService;
    @Autowired
    private CommService commService;

    @Override
    public ViewDto saveView(ViewDto viewDto) {
        ViewModel viewModel = viewService.parseViewModel(viewDto);
        boolean flag = viewService.saveOrUpdate(viewModel);
        if (!flag) {
            throw new SaveException("保存视图异常");
        }
        viewDto.setId(viewModel.getId());
        // 保存维度
        if (!CollectionUtils.isEmpty(viewDto.getDimensions())) {
            viewDto.getDimensions().forEach(dimensionDto -> dimensionDto.setViewId(viewDto.getId()));
            saveDimensions(viewDto.getDimensions());
        }
        // 保存指标
        if (!CollectionUtils.isEmpty(viewDto.getMeasures())) {
            viewDto.getMeasures().forEach(measureDto -> measureDto.setViewId(viewDto.getId()));
            saveMeasures(viewDto.getMeasures());
        }
        // 保存过滤条件
        if (!CollectionUtils.isEmpty(viewDto.getConfigFilters())) {
            viewDto.getConfigFilters().forEach(
                    filterDataDto ->
                            filterDataDto.setFilterEnum(FilterEnum.view_config)
                                    .setAssociatedId(viewDto.getId())
            );
        }
        return viewDto;
    }

    @Override
    public List<ViewDto> saveViews(List<ViewDto> viewDtoList) {
        viewDtoList.forEach(this::saveView);
        return viewDtoList;
    }

    @Override
    public ViewDto getViewById(Long id) {
        ViewModel viewModel = viewService.getById(id);
        if (Objects.isNull(viewModel)) {
            log.error("查询视图不存在,视图ID={}", id);
            throw new GetException("查询视图不存在");
        }
        ViewDto viewDto = viewService.parseViewDto(viewModel);
        // 获取数据源
        DataSourceDto dataSourceDto = dataSourceAggService.getDataSource(viewDto.getDsId());
        viewDto.setDataSource(dataSourceDto);
        // 获取维度
        List<DimensionDto> dimensionDtoList = getDimensionsByViewId(viewDto.getId());
        viewDto.setDimensions(dimensionDtoList);
        // 获取指标
        List<MeasureDto> measureDtoList = getMeasuresByViewId(viewDto.getId());
        viewDto.setMeasures(measureDtoList);
        // 获取过滤条件
        List<FilterDataDto> filterDataDtoList = filterAggService.getsByAssociatedIdAndFilterType(viewDto.getId(), FilterEnum.view_config.getCode());
        viewDto.setConfigFilters(filterDataDtoList);
        // 获取结果过滤条件
        List<FilterDataDto> dimensionResultFilterList = filterAggService.getsByAssociatedIdAndFilterType(viewDto.getId(), FilterEnum.dimension_result.getCode());
        List<FilterDataDto> measureResultFilterList = filterAggService.getsByAssociatedIdAndFilterType(viewDto.getId(), FilterEnum.measure_result.getCode());
        List<FilterDataDto> resultFilterList = new ArrayList<>();
        resultFilterList.addAll(dimensionResultFilterList);
        resultFilterList.addAll(measureResultFilterList);
        viewDto.setResultFilters(resultFilterList);
        return viewDto;
    }

    @Override
    public DimensionDto saveDimension(DimensionDto dimensionDto) {
        DimensionModel dimensionModel = dimensionService.parseDimensionModel(dimensionDto);
        boolean flag = dimensionService.saveOrUpdate(dimensionModel);
        if (!flag) {
            throw new SaveException("保存维度异常");
        }
        dimensionDto.setId(dimensionModel.getId());
        return dimensionDto;
    }

    @Override
    public List<DimensionDto> saveDimensions(List<DimensionDto> dimensionDtoList) {
        dimensionDtoList.forEach(this::saveDimension);
        return dimensionDtoList;
    }

    @Override
    public List<DimensionDto> getDimensionsByViewId(Long viewId) {
        List<DimensionModel> dimensionModels = dimensionService.getDimensionsByViewId(viewId);
        List<DimensionDto> dimensionDtoList = dimensionModels.stream().map(dimensionModel -> dimensionService.parseDimensionDto(dimensionModel)).collect(Collectors.toList());
        return dimensionDtoList;
    }

    @Override
    public MeasureDto saveMeasure(MeasureDto measureDto) {
        MeasureModel measureModel = measureService.parseMeasureModel(measureDto);
        boolean flag = measureService.saveOrUpdate(measureModel);
        if (!flag) {
            throw new SaveException("保存指标异常");
        }
        measureDto.setId(measureModel.getId());
        return measureDto;
    }

    @Override
    public List<MeasureDto> saveMeasures(List<MeasureDto> measureDtoList) {
        measureDtoList.forEach(this::saveMeasure);
        return measureDtoList;
    }

    @Override
    public List<MeasureDto> getMeasuresByViewId(Long viewId) {
        List<MeasureModel> measureModels = measureService.getMeasuresByViewId(viewId);
        List<MeasureDto> measureDtoList = measureModels.stream().map(measureModel -> measureService.parseMeasureDto(measureModel)).collect(Collectors.toList());
        return measureDtoList;
    }

    @Override
    public ViewDto getViewAndDataById(Long id, String filters, String having, String links, String jumps, String drills) {
        ViewDto viewDto = getViewById(id);
        getViewData(viewDto, filters, having, links, jumps, drills);
        return viewDto;
    }

    @Override
    public ActionDto saveAction(ActionDto actionDto) {
        ActionModel actionModel = actionService.parseActionModel(actionDto);
        boolean flag = actionService.saveOrUpdate(actionModel);
        if (!flag) {
            throw new SaveException("保存行为异常");
        }
        actionDto.setId(actionModel.getId());
        return actionDto;
    }

    @Override
    public List<ActionDto> saveActions(List<ActionDto> actionDtoList) {
        actionDtoList.forEach(this::saveAction);
        return actionDtoList;
    }

    /**
     * 过滤组件数据
     *
     * @param viewDto
     * @param filters
     * @return
     */
    private ViewDto filterComponent(ViewDto viewDto, String filters) {
        // TODO 过滤组件
        if (StringUtils.isBlank(filters)) {
            return viewDto;
        }
        List<Map<String, String>> list = GsonUtil.getGson().fromJson(filters, List.class);
        if(CollectionUtils.isEmpty(list)){
            return viewDto;
        }
        list.forEach(map -> {
            FilterComponentModel filterComponentModel = filterComponentService.getById(Long.parseLong(map.get("id")));
            // 关联视图
            List<ActionModel> actionModels = actionService.getListByModel(
                    new ActionModel().setActionType(ActionTypeEnum.filter.getCode())
                            .setSourceId(filterComponentModel.getId())
                            .setSourceEntityKey(filterComponentModel.getEntityKey())
                            .setSourceItemKey(filterComponentModel.getItemKey())
                            .setTargetId(viewDto.getId())
            );
            if (!CollectionUtils.isEmpty(actionModels)) {
                List<FilterDataDto> filterDataDtoList = actionModels.stream().map(actionModel -> {
                    FilterDataDto filterDataDto = new FilterDataDto();
                    filterDataDto.setRelation(RelationEnum.and)
                            .setOperator(OperatorEnum.getEnumByCode(filterComponentModel.getOperatorType()))
                            .setEntityKey(actionModel.getTargetEntityKey())
                            .setItemKey(actionModel.getTargetItemKey())
                            .setValueData(GsonUtil.format(map.get("value")));
                    return filterDataDto;
                }).collect(Collectors.toList());
                viewDto.getConfigFilters().addAll(filterDataDtoList);
            }
        });
        return viewDto;
    }

    @Override
    public ViewDto getViewData(ViewDto viewDto, String filters, String having, String links, String jumps, String drills) {
        if (Objects.isNull(viewDto.getDataSource())) {
            DataSourceDto dataSource = dataSourceAggService.getDataSource(viewDto.getDsId());
            viewDto.setDataSource(dataSource);
        }
        // filters 过滤组件
        filterComponent(viewDto, filters);
        // link 联动
        viewLink(viewDto, links);
        // 跳转
        jump(viewDto, jumps);
        // drill 钻取
        viewDrill(viewDto, drills);
        // 结果过滤
        resultFilter(viewDto, having);
        // 拼sql
        Select select = sqlAssemblyService.AssemblySql(viewDto);
        List<Map<String, Object>> dataList = commService.getList(select.toString());
        viewDto.setData(dataList);
        commService.getDataInList(viewDto);
        // 指标数据格式化
        Optional.of(viewDto.getMeasures()).ifPresent(measureDtoList -> measureService.formatMeasure(measureDtoList));
        // 图表数据转换
        ChartDataService strategy = sqlAssemblyService.getStrategy(viewDto.getChartEnum().getType());
        strategy.getData(viewDto);
        return viewDto;
    }

    /**
     * 视图结果过滤
     *
     * @param viewDto
     * @param having
     * @return
     */
    private ViewDto resultFilter(ViewDto viewDto, String having) {
        // TODO 结果过滤
        return null;
    }

    /**
     * 视图钻取
     *
     * @param viewDto
     * @param drill
     * @return
     */
    private ViewDto viewDrill(ViewDto viewDto, String drill) {
        // TODO 钻取
        return null;
    }

    /**
     * 跳转
     *
     * @param viewDto
     * @param jump
     * @return
     */
    private ViewDto jump(ViewDto viewDto, String jump) {
        // TODO 跳转
        return null;
    }

    /**
     * 视图联动
     *
     * @param viewDto
     * @param links
     * @return
     */
    private ViewDto viewLink(ViewDto viewDto, String links) {
        // TODO 视图联动
        if (StringUtils.isBlank(links)) {
            return viewDto;
        }
        List<ParameterDto> parameters = GsonUtil.getGson().fromJson(links, List.class);
        if(CollectionUtils.isEmpty(parameters)){
            return viewDto;
        }
        for (ParameterDto parameter : parameters) {
            if (viewDto.getId().equals(parameter.getId())) {
                continue;
            }

            List<ActionModel> actionModels = actionService.getListByModel(
                    new ActionModel().setSourceId(parameter.getId())
                            .setTargetId(viewDto.getId())
                            .setSourceEntityKey(parameter.getEntityKey())
                            .setSourceItemKey(parameter.getItemKey())
            );
            if (!CollectionUtils.isEmpty(actionModels)) {
                List<FilterDataDto> filterDataDtoList = actionModels.stream().map(actionModel -> {
                    FilterDataDto filterDataDto = new FilterDataDto();
                    filterDataDto.setRelation(RelationEnum.and)
                            .setOperator(OperatorEnum.in)
                            .setEntityKey(actionModel.getTargetEntityKey())
                            .setItemKey(actionModel.getTargetItemKey())
                            .setValueData(GsonUtil.format(parameter.getValue()));
                    return filterDataDto;
                }).collect(Collectors.toList());
                viewDto.getConfigFilters().addAll(filterDataDtoList);
            } else {
                if (viewDto.getDsId().equals(parameter.getDsId())) {
                    FilterDataDto filterDataDto = new FilterDataDto();
                    filterDataDto.setRelation(RelationEnum.and)
                            .setOperator(OperatorEnum.in)
                            .setEntityKey(parameter.getEntityKey())
                            .setItemKey(parameter.getItemKey())
                            .setValueData(GsonUtil.format(parameter.getValue()));
                    viewDto.getConfigFilters().add(filterDataDto);
                }
            }

        }
        return viewDto;
    }
}
